package main

import (
	"errors"
	"log"
	"net"
	"os"
	"time"

	"golang.org/x/net/ipv4"
)

const bufSize = 8192

func main() {
	// DeviceService()
	// list, _ := net.Interfaces()
	// log.Printf("%#v\n", list[2])
	// return
	// probeSOAP := `<?xml version="1.0" encoding="UTF-8"?>
	// <Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
	// <Header>
	// <a:Action mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>
	// <a:MessageID>uuid:78a2ed98-bc1f-4b08-9668-094fcba81e30</a:MessageID><a:ReplyTo>
	// <a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
	// </a:ReplyTo><a:To mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>
	// </Header>
	// <Body><Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">
	// <d:Types xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</d:Types>
	// </Probe>
	// </Body>
	// </Envelope>`
	probeSOAP := `<?xml version="1.0" encoding="UTF-8"?>
	<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
	<Header>
	<a:Action mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>
	<a:MessageID>ulid:01ABCD</a:MessageID><a:ReplyTo>
	<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
	</a:ReplyTo><a:To mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>
	</Header>
	<Body><Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">
	<d:Types xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</d:Types>
	</Probe>
	</Body>
	</Envelope>`

	list, _ := net.Interfaces()
	for _, interfa := range list {
		log.Printf("%#v\n", interfa)
		if interfa.Flags != 0x33 {
			continue
		}
		log.Println(sendUDPMulticast(probeSOAP, interfa.Name))
	}
	// log.Println(sendUDPMulticast(probeSOAP, "WLAN"))
	// log.Println(sendUDPMulticast(probeSOAP, "以太网"))
}

func sendUDPMulticast(msg string, interfaceName string) ([]string, error) {
	c, err := net.ListenPacket("udp4", "0.0.0.0:0")
	if err != nil {
		return nil, err
	}
	defer c.Close()

	iface, err := net.InterfaceByName(interfaceName)
	if err != nil {
		return nil, err
	}

	p := ipv4.NewPacketConn(c)
	group := net.IPv4(239, 255, 255, 250)
	if err := p.JoinGroup(iface, &net.UDPAddr{IP: group}); err != nil {
		return nil, err
	}

	dst := &net.UDPAddr{IP: group, Port: 3702}
	data := []byte(msg)
	// for _, ifi := range []*net.Interface{iface} {
	if err := p.SetMulticastInterface(iface); err != nil {
		return nil, err
	}
	p.SetMulticastTTL(2)
	if _, err := p.WriteTo(data, nil, dst); err != nil {
		return nil, err
	}
	// }

	if err := p.SetReadDeadline(time.Now().Add(time.Second * 1)); err != nil {
		return nil, err
	}

	var result []string
	for {
		b := make([]byte, bufSize)
		n, _, src, err := p.ReadFrom(b)
		if err != nil {
			if !errors.Is(err, os.ErrDeadlineExceeded) {
				return nil, err
			}
			break
		}
		log.Println("--------------", src)
		result = append(result, string(b[0:n]))
	}
	return result, nil
}
